package com.mals.pingpong;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.RectShape;
import android.view.SurfaceHolder;

/**
 * Class that controls the main part of the program logic. In this class we have
 * the variables that define the position of the different elements in the View.
 * 
 * @author marcosal
 * 
 */
public class PingPongThread extends Thread {

	// drawable elements
	private ShapeDrawable ball;
	private ShapeDrawable barl;
	private ShapeDrawable barr;
	private ShapeDrawable baru;
	private ShapeDrawable bard;

	// SurfaceHolder
	private SurfaceHolder surfaceHolder;

	// controls the execution of the thread
	private boolean doRun = false;

	// variables used by the ball image to define
	// the position, direction and speed
	private int ballxpos;
	private int ballypos;
	private int ballxdir;
	private int ballydir;
	private int ballspeed = 1;

	// bar speed
	private static final int barspeed = 10;
	// varaibles that define the bars position
	// and size
	private int barlypos;
	private int barlwidth = 200;
	private int barrypos;
	private int barrwidth = 200;
	private int baruxpos;
	private int baruwidth = 200;
	private int bardxpos;
	private int bardwidth = 200;

	// screen boundaries
	private int screenHeight;
	private int screenWidth;

	/**
	 * In the constructor we define some values that are going to be constant on
	 * the game.
	 * 
	 * @param surfaceHolder
	 * @param screenWidth
	 * @param screenHeight
	 */
	public PingPongThread(SurfaceHolder surfaceHolder, int screenWidth,
			int screenHeight) {
		this.surfaceHolder = surfaceHolder;
		this.screenWidth = screenWidth;
		this.screenHeight = screenHeight;

		// we center the bars in the middle of the screen height
		barlypos = screenHeight / 2;
		barrypos = screenHeight / 2;
		baruxpos = screenWidth / 2;
		bardxpos = screenWidth / 2;

		// we center the ball in the middle of the screen
		ballxpos = screenWidth / 2;
		ballypos = screenHeight / 2;

		// create the drawable instances
		ball = new ShapeDrawable(new OvalShape());
		barl = new ShapeDrawable();
		barr = new ShapeDrawable();
		baru = new ShapeDrawable();
		bard = new ShapeDrawable();
	}

	/**
	 * Defines if the thread must be running
	 * 
	 * @param run
	 */
	public void setRunning(boolean run) {
		doRun = run;
	}

	/**
	 * Let other classes to define x position of the ball
	 * 
	 * @param ballxpos
	 */
	public void setBallxpos(int ballxpos) {
		this.ballxpos = ballxpos;
	}

	/**
	 * Let other classes to define y position of the ball
	 * 
	 * @param ballypos
	 */
	public void setBallypos(int ballypos) {
		this.ballypos = ballypos;
	}

	/**
	 * Let other classes to define y position of the bar 1
	 * 
	 * @param bar1ypos
	 *            the bar1ypos to set
	 */
	public void setBarlypos(float angle) {
		if (angle > 0) {
			barlypos = barlypos + barlwidth > screenHeight ? screenHeight : barlypos + barspeed;
		} else if (angle < 0) {
			barlypos = barlypos < 0 ? 0 : barlypos - barspeed;
		}
	}

	/**
	 * Let other classes to define y position of the bar 1
	 * 
	 * @param bar2ypos
	 *            the bar2ypos to set
	 */
	public void setBarrypos(float angle) {
		if (angle > 0) {
			barrypos = barrypos < 0 ? 0 : barrypos - barspeed;
		} else if (angle < 0) {
			barrypos = barrypos + barrwidth > screenHeight ? screenHeight : barrypos + barspeed;
		}
	}
	
	public void setBaruxpos(float angle) {
		if (angle > 0) {
			baruxpos = baruxpos < 0 ? 0 : baruxpos - barspeed;
		} else if (angle < 0) {
			baruxpos = baruxpos + baruwidth > screenWidth ? screenWidth : baruxpos + barspeed;
		}
	}
	
	public void setBardxpos(float angle) {
		if (angle > 0) {
			bardxpos = bardxpos + bardwidth > screenWidth ? screenWidth : bardxpos + barspeed;
		} else if (angle < 0) {
			bardxpos = bardxpos < 0 ? 0 : bardxpos - barspeed;
		}
	}

	/**
	 * Main thread method. It's a finite cycle that update the view using
	 * auxiliary methods found in this class.
	 */
	@Override
	public void run() {
		Canvas c;
		RectShape eraser = new RectShape();
		eraser.resize(screenWidth, screenHeight);
		Paint p = new Paint();
		p.setARGB(100, 0, 0, 0);
		while (doRun) {
			c = null;
			try {
				c = surfaceHolder.lockCanvas(null);
				synchronized (surfaceHolder) {
					updateBallPosition();
					updateBarsPosition();
					eraser.draw(c, p);
					ball.draw(c);
					barl.draw(c);
					barr.draw(c);
					baru.draw(c);
					bard.draw(c);
					c.drawText("barl: " + barlypos + "", 50, 50, new Paint());
				}
			} finally {
				// do this in a finally so that if an exception is thrown
				// during the above, we don't leave the Surface in an
				// inconsistent state
				if (c != null) {
					surfaceHolder.unlockCanvasAndPost(c);
				}
			}
		}
	}

	/**
	 * Draws the bars using the variables that let us know what position and
	 * width will they have.
	 */
	private void updateBarsPosition() {
		barl.getPaint().setColor(0xff74AC23);
		barr.getPaint().setColor(0xff74AC23);
		baru.getPaint().setColor(0xff74AC23);
		bard.getPaint().setColor(0xff74AC23);

		barl.setBounds(10, barlypos, 20, barlypos + barlwidth);
		barr.setBounds(screenWidth - 20, barrypos, screenWidth - 10, barrypos
				+ barrwidth);
		baru.setBounds(baruxpos, 10, baruxpos + baruwidth, 20);
		bard.setBounds(bardxpos,  screenHeight - 100, bardxpos + bardwidth, screenHeight - 90);
	}

	/**
	 * This function performs all the position and collision logic.
	 */
	private void updateBallPosition() {

		// check collisions 
		if ((ballxpos >= screenWidth - 15 && ballxpos <= screenWidth)
				&& (ballypos >= barrypos && ballypos <= barrypos + barrwidth)) {
			ballxdir = 0;
		} else if ((ballxpos >= 0 && ballxpos <= 15)
				&& (ballypos >= barlypos && ballypos <= barlypos + barlwidth)) {
			ballxdir = 1;
		} else if ((ballypos >= screenHeight - 15 && ballypos <= screenHeight)
				&& (ballxpos >= bardxpos && ballypos <= bardxpos + bardwidth)) {
			ballydir = 0;  
			
		} else if ((ballypos >= 0 && ballypos <= 15)
				&& (ballxpos >= baruxpos && ballxpos <= baruxpos + baruwidth)) {
			ballydir = 1;
		}
			
		// the ball is outside of the canvas
		if (ballxpos < 0 || ballxpos > screenWidth) {
			ballxpos = screenWidth / 2;
			ballypos = screenHeight / 2;
			ballxdir = 1;
		}
		// the ball is outside the canvas
		if (ballypos < 0 || ballypos > screenHeight) {
			ballxpos = screenWidth / 2;
			ballypos = screenHeight / 2;
			ballydir = 1;
		}

//		if (ballypos > screenHeight - 5) {
//			ballydir = 0;
//		} else if (ballypos < 5) {
//			ballydir = 1;
//		}

		if (ballxdir == 0) {
			ballxpos -= ballspeed;
		} else {
			ballxpos += ballspeed;
		}

		if (ballydir == 0) {
			ballypos -= ballspeed;
		} else {
			ballypos += ballspeed;
		}

		if (ballxpos > screenWidth) {
			ballxdir = 0;
		} else if (ballxpos < 0) {
			ballxdir = 1;
		}

		if (ballypos > screenHeight) {
			ballydir = 0;
		} else if (ballypos < 0) {
			ballydir = 1;
		}

		ball.getPaint().setColor(0xff74AC23);
		ball.setBounds(ballxpos, ballypos, ballxpos + 10, ballypos + 10);
	}
}
